/*=+--+=#=+--     Unmanned Aerial System Management Software      --+=#=+--+=#*\
|          Copyright (C) 2011 Regents of the University of Colorado.           |
|                             All Rights Reserved.                             |

     This program is free software: you can redistribute it and/or modify
     it under the terms of the GNU General Public License version 2 as
     published by the Free Software Foundation.

     This program is distributed in the hope that it will be useful,
     but WITHOUT ANY WARRANTY; without even the implied warranty of
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     GNU General Public License for more details.

     You should have received a copy of the GNU General Public License
     along with this program.  If not, see <http://www.gnu.org/licenses/>.

            Jack Elston                       Cory Dixon                        
|           elstonj@colorado.edu              dixonc@colorado.edu              |
|                                                                              |
\*=+--+=#=+--                 --+=#=+--+=#=+--                    --+=#=+--+=#*/

/***********************************************************************
 *
 * FILENAME:
 * vcLogParser.cxx
 *
 * PURPOSE: 
 *  Parse the VirtualCockpit log files into a csv file vcConfig.h
 *
 * CREATED:
 * 02/2005 by Cory Dixon
 *
 ***********************************************************************/

#include <unistd.h>
#include <iostream>
#include <fstream>
#include <iomanip>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>

#include "fileLog.h"
#include "timeLib.h"
#include "type_defs.h"
#include "command.h"
#include "queue.h"

#include <string>

#define CSV_CHAR "\t"

// functions
void parseCommand(const Command &cmd);
void ProcessOutput(char *buf, int nRead);

//
// global variables
//
LogFileStruct line;
CommandQueue        queue;     // parse incoming linkPort stream

long int totalBytes=0;
long int numCommands=0;
long int numBadHeader=0;
long int numBadCSUM=0;

long int cmdCount[CMD_MAX_NUM] = { 0 };
long int cmdCountBad[CMD_MAX_NUM] = { 0 };

int NumCommandsToSave = 0;
unsigned char CommandsToSave[256] = { 0 };

ofstream of;

int svn_ver = -1; // svn version within log file
int compiled_ver = -1; // svn version when this was compiled

//string cmdSequenceFileName = "command_sequence.dat";
//ofstream cmdSequenceFile;
//string cmdNumberFileName = "command_numbers.dat";
//ofstream cmdNumberFile;

//----------------------------------------------------------
// Main function
//----------------------------------------------------------
int main(int argc, char *argv[])
{
	string inFileStr;
	string outFileStr;

	if( argc >=  2) {
		//inFileStr = argv[1] + string(".log");
		inFileStr = argv[1];
		outFileStr = argv[1] + string(".csv");
	} else {
		cout << argv[0] << " {logFile} [cmd1 cmd2 cmd3 ...]" << endl;
		exit(0);
	}
	NumCommandsToSave = 255;
	CommandsToSave[0] = 255;

	for(int i=0; i < argc - 2; i++) {
		int cmd = atoi( argv[i+2] );
		if( cmd == -1 ) {
			NumCommandsToSave = -1;
		} else if( cmd == 0 || cmd == 255 ) {
			//NumCommandsToSave = cmd;
			//CommandsToSave[0] = cmd;
			i = argc;
		} else {
			CommandsToSave[i] = atoi( argv[i+2] );
			NumCommandsToSave++;
		}	
	}

	FileLog vcLog(NULL, FileLog::READ);
	int bytesRead;
	struct tm tmTime;

	if( ! vcLog.open(inFileStr.c_str()) ) {
		cout << "Could not open " << inFileStr << endl;
		return ERROR;
	}

	// open the output file
	of.open(outFileStr.c_str(), ios::out);
	if( !of ) {
		cout << "Could not open " << outFileStr << endl;
		return ERROR;
	}

	if( NumCommandsToSave != -1 ) {
		// open the command sequence file
		//cmdSequenceFile.open(cmdSequenceFileName.c_str(), ios::out);
		//if( !cmdSequenceFile ) {
		//cout << "Could not open " << cmdSequenceFileName << endl;
		//return ERROR;
		//}

		// open the command sequence file
		//cmdNumberFile.open(cmdNumberFileName.c_str(), ios::out);
		//if( !cmdSequenceFile ) {
		//cout << "Could not open " << cmdNumberFileName << endl;
		//return ERROR;
		//}
	}

	// after first read, can get time struct tm
	bytesRead = vcLog.read( line );
	tmTime = vcLog.getTime();

	cout << "File: " << inFileStr << " - " << vcLog.fileSize() << " [bytes]" << endl
		<< "-------------------------" << endl
		<< " year=" << tmTime.tm_year + 1900
		<< " month=" << tmTime.tm_mon + 1
		<< " day=" << tmTime.tm_mday 
		<< " hour=" << tmTime.tm_hour 
		<< " min=" << tmTime.tm_min 
		<< " sec=" << tmTime.tm_sec 
		<< " version=" << vcLog.getVersion() << endl;

	svn_ver = vcLog.getVersion();
	compiled_ver = atoi( SVN_VER );

	cout << endl << "Parsing Command Set (SVN=" << compiled_ver << ") :\n";
	if(NumCommandsToSave == 255 ) {
		for( int i=0; i < CMD_MAX_NUM; i++)
			if(DefinedCommands[i].id == i)
				cout << "\t\t0x"  << hex << i << " " << DefinedCommands[ i ].name << ",\n";
	} else {
		for( int i=0; i < NumCommandsToSave; i++)
			cout << "\t\t0x" << hex << i  << " " << DefinedCommands[ CommandsToSave[i] ].name << ",\n";
	}
	cout << dec << endl;

	ProcessOutput(line.bytes, line.numOfBytes);

	while( (bytesRead = vcLog.read( line )) > 0 ) {
		ProcessOutput(line.bytes, line.numOfBytes);
	}

	cout << endl;

	cout << endl
		<< setw(20) << "CMD" << setw(7) << "count" << setw(5) << "bad" <<  endl
		<< "---------------------------------------" << endl;
	for( int i=0; i < CMD_MAX_NUM; i++ )
		if( cmdCount[i] != 0 || cmdCountBad[i] != 0){
			cout << setw(20) << DefinedCommands[ i ].name << setw(7) << cmdCount[i] << setw(5) << cmdCountBad[i] << endl;
		}


	cout << endl 
		<< setw(25) << "Stats" << setw(10) << "Value" << endl
		<< "---------------------------------------" << endl
		<< setw(25) << "bytes logged" << " = " << totalBytes << " (" << totalBytes/1024.0 << " kB)"
		<< endl;

	if( NumCommandsToSave != -1 ) {
		cout << setw(25) << "bad header bytes" << " = " << numBadHeader
			<< " (" << (numBadHeader) / (float)(totalBytes) * 100.0 << "%)"
			<< endl << setw(25) << "bad csum bytes" << " = " << numBadCSUM
			<< " (" << (numBadCSUM) / (float)(totalBytes) * 100.0 << "%)"
			<< endl << setw(25) << "total dropped bytes" << " = " << numBadCSUM + numBadHeader 
			<< " (" << (numBadCSUM + numBadHeader) / (float)(totalBytes) * 100.0 << "%)"
			<< endl << setw(25) << "processed commands" << " = " << numCommands
			<< endl << setw(25) << "estimated lost commands" << " = " << numBadCSUM 
			<< " (" << (numBadCSUM) / (float)(numCommands) * 100.0 << "%)"
			<< endl;

		//cmdNumberFile.close();
		//cmdSequenceFile.close();
	}
	vcLog.close();
	of.close();

	// exit
	return OK;
}

void ProcessOutput(char *buf, int nRead)
{
	totalBytes += nRead;

	if( NumCommandsToSave != -1 ) {
		queue.push((uint8_t *)buf,nRead);

		while( queue.length() >= CMD_PACKET_SIZE ) {
			// check the cmd and numParams bytes
			if( queue.needMoreBytes() ) 
				break;
			else {
				//if( queue.isDefined() ) {
				if( queue.isValid() ){
					//cout << "-- Parsing CMD --" << endl;
					Command rxCmd = queue.popCommand();

					// gather stats and save sequence file
					cmdCount[ rxCmd.cmd() ]++;
					numCommands++;
					//cmdSequenceFile << "1" << endl;

					// check to see if this command is desired by user to be saved
					if( CommandsToSave[0] == 255 )
						parseCommand(rxCmd);
					else if( CommandsToSave[0] != 0 )
						for( int i = 0; i < NumCommandsToSave; i++ )
							if( CommandsToSave[i] == rxCmd.cmd() ) 
								parseCommand(rxCmd);
				} else {
					//cout << endl << queue.peekCommand();
					unsigned char byte = queue.popByte();
					numBadCSUM++;
					cmdCountBad[ byte ]++;
					//cmdSequenceFile << "0" << endl;

#if 1
					//cout << "!! Dropping byte for bad csum: 0x" << hex << (int)byte << dec << " --" << endl;
					cout << "-";
#endif
				}
				//} 
				/*else {
				  unsigned char byte;
				  byte = queue.popByte();
				  numBadHeader++;
#if 1
				//cout << "!! Dropping byte for bad header: 0x" << hex << (int)byte << dec << " --" << endl;
				cout << "#";
#endif
}
*/
}
}
	} else {
		of << setprecision(15) 
			<< (float) line.timeOfDay << CSV_CHAR
			<< buf << CSV_CHAR
			<< endl;
	}
}

void parseCommand(const Command &cmd)
{
	// copy params into a buffer
	unsigned char buf[ CMD_MAX_SIZE ];
	cmd.copyToBuf(buf);
	char * dataPtr = (char *)(buf + CMD_HEADER_SIZE);

	switch( cmd.cmd() )
	{

		case CMD_GPS_LATLON:
			GPSLatLon_t ll;
			CopyBufToStruct(dataPtr, ll);

			// write the data packet to the output file
			of << setprecision(15) 
				<< (float) line.timeOfDay << CSV_CHAR;
			of << inet_ntoa(line.from) << CSV_CHAR
				<< inet_ntoa(line.to) << CSV_CHAR;
			of << setprecision(15) 
				<< (float) cmd.cmd() << CSV_CHAR
				<< (float) cmd.seq() << CSV_CHAR 
				<< (float) ll.lat << CSV_CHAR
				<< (float) ll.lon << CSV_CHAR
				<< endl;
			break;

		case CMD_GPS_UTC:
			GPSUTC_t utc;
			CopyBufToStruct(dataPtr, utc);

			// write the data packet to the output file
			of << setprecision(15) 
				<< (float) line.timeOfDay << CSV_CHAR;
			of << inet_ntoa(line.from) << CSV_CHAR
				<< inet_ntoa(line.to) << CSV_CHAR;
			of << setprecision(15) 
				<< (float) cmd.cmd() << CSV_CHAR
				<< (float) cmd.seq() << CSV_CHAR
				<< (float) utc.hours << CSV_CHAR
				<< (float) utc.minutes << CSV_CHAR
				<< (float) utc.seconds << CSV_CHAR
				<< endl;
			break;

		case CMD_GPS_TRACK:
			GPSTrack_t track;
			CopyBufToStruct(dataPtr, track);

			// write the data packet to the output file
			of << setprecision(15) 
				<< (float) line.timeOfDay << CSV_CHAR;
			of << inet_ntoa(line.from) << CSV_CHAR
				<< inet_ntoa(line.to) << CSV_CHAR;
			of << setprecision(15) 
				<< (float) cmd.cmd() << CSV_CHAR
				<< (float) cmd.seq() << CSV_CHAR
				<< (float) track.tru << CSV_CHAR
				<< (float) track.magnetic << CSV_CHAR
				<< endl;
			break;

		case CMD_GPS_ALT:
			GPSAlt_t alt;
			CopyBufToStruct(dataPtr, alt);

			// write the data packet to the output file
			of << setprecision(15) 
				<< (float) line.timeOfDay << CSV_CHAR;
			of << inet_ntoa(line.from) << CSV_CHAR
				<< inet_ntoa(line.to) << CSV_CHAR;
			of << setprecision(15) 
				<< (float) cmd.cmd() << CSV_CHAR
				<< (float) cmd.seq() << CSV_CHAR
				<< (float) alt.value << CSV_CHAR
				<< endl;
			break;

		case CMD_GOTO_WP:
			GotoWP_t wpt;
			CopyBufToStruct(dataPtr, wpt);
			break;
#if 0
		case CMD_WAYPT:
			Waypt_t wpt;
			CopyBufToStruct(dataPtr, wpt);

			/*			// write the data packet to the output file
						of << setprecision(15) 
						<< (float) line.timeOfDay << CSV_CHAR
						<< (float) line.from << CSV_CHAR
						<< (float) line.to << CSV_CHAR
						<< (float) cmd.cmd() << CSV_CHAR
						<< (float) cmd.seq() << CSV_CHAR
						<< (float) wpt.value << CSV_CHAR
						<< endl;*/
			break;
#endif

		case CMD_STREAM_REQ:
			StreamReq_t request;
			CopyBufToStruct(dataPtr, request);
			of << setprecision(15) 
				<< (float) line.timeOfDay << CSV_CHAR;
			of << inet_ntoa(line.from) << CSV_CHAR
				<< inet_ntoa(line.to) << CSV_CHAR;
			of << setprecision(15) 
				<< (float) cmd.cmd() << CSV_CHAR
				<< (float) cmd.seq() << CSV_CHAR
				<< (float) request.id << CSV_CHAR
				<< inet_ntoa(request.client) << CSV_CHAR
				<< (float) request.port << CSV_CHAR
				<< (float) request.send_data << CSV_CHAR
				<< endl;
			break;

		case CMD_COORDINATE:
			Coordinate_t coordinate;
			CopyBufToStruct(dataPtr, coordinate);
			of << setprecision(15) 
				<< (float) line.timeOfDay << CSV_CHAR;
			of << inet_ntoa(line.from) << CSV_CHAR
				<< inet_ntoa(line.to) << CSV_CHAR;
			of << setprecision(15) 
				<< (float) cmd.cmd() << CSV_CHAR
				<< (float) cmd.seq() << CSV_CHAR
				<< inet_ntoa(coordinate.partner) << CSV_CHAR
				<< (bool) coordinate.requesting << CSV_CHAR
				<< endl;
			break;

		case CMD_GPS_TELEM:
			GPSTelem_t gps_telemetry;
			CopyBufToStruct(dataPtr, gps_telemetry);

			// write the data packet to the output file
			of << setprecision(15) 
				<< (float) line.timeOfDay << CSV_CHAR;
			of << inet_ntoa(line.from) << CSV_CHAR
				<< inet_ntoa(line.to) << CSV_CHAR;
			of << setprecision(15) 
				<< (float) cmd.cmd() << CSV_CHAR
				<< (float) cmd.seq() << CSV_CHAR
				<< (int)   gps_telemetry.utc.hours << CSV_CHAR
				<< (int)   gps_telemetry.utc.minutes << CSV_CHAR
				<< (float) gps_telemetry.utc.seconds << CSV_CHAR
				<< (float) gps_telemetry.pos.lat << CSV_CHAR
				<< (float) gps_telemetry.pos.lon << CSV_CHAR
				<< (float) gps_telemetry.pos.alt << CSV_CHAR
				<< (float) gps_telemetry.track << CSV_CHAR
				<< (float) gps_telemetry.sog << CSV_CHAR
				<< endl;
			break;

		case CMD_TELEM:
			Telemetry_t telemetry;
			CopyBufToStruct(dataPtr, telemetry);

			// write the data packet to the output file
			of << setprecision(15) 
				<< (float) line.timeOfDay << CSV_CHAR;
			of << inet_ntoa(line.from) << CSV_CHAR
				<< inet_ntoa(line.to) << CSV_CHAR;
			of << setprecision(15) 
				<< (float) cmd.cmd() << CSV_CHAR
				<< (float) cmd.seq() << CSV_CHAR
				<< (int)   telemetry.gps.utc.hours << CSV_CHAR
				<< (int)   telemetry.gps.utc.minutes << CSV_CHAR
				<< (float) telemetry.gps.utc.seconds << CSV_CHAR
				<< (float) telemetry.gps.pos.lat << CSV_CHAR
				<< (float) telemetry.gps.pos.lon << CSV_CHAR
				<< (float) telemetry.gps.pos.alt << CSV_CHAR
				<< (float) telemetry.gps.track << CSV_CHAR
				<< (float) telemetry.gps.sog << CSV_CHAR
				<< (float) telemetry.airdata.tas << CSV_CHAR
				<< (float) telemetry.airdata.alt << CSV_CHAR
				<< (float) telemetry.angles.roll << CSV_CHAR
				<< (float) telemetry.angles.pitch << CSV_CHAR
				<< (float) telemetry.angles.yaw << CSV_CHAR;
#ifdef SVN_VER 
			of << setprecision(15)
				<< (int) telemetry.navigation.APon << CSV_CHAR
				<< (int) telemetry.navigation.MAmode << CSV_CHAR
				<< (int) telemetry.navigation.APmode << CSV_CHAR
				<< (int) telemetry.navigation.waypt << CSV_CHAR
				<< (int) telemetry.navigation.OBmode << CSV_CHAR
				<< (int) telemetry.navigation.OBtype << CSV_CHAR
				<< (int) telemetry.navigation.value << CSV_CHAR;
#else
			of << setprecision(15)
				<< (int) telemetry.navigation.AP << CSV_CHAR
				<< (int) *((uint16_t *)&telemetry.navigation.waypt) << CSV_CHAR;
#endif 
			of << setprecision(15)
				<< (int) telemetry.system.availableForCommand << CSV_CHAR
				<< (float) telemetry.system.twelveV << CSV_CHAR
				<< (float) telemetry.system.fiveV << CSV_CHAR
				<< endl;
			break;

		case CMD_SONDE:
			Sonde_t sonde;
			CopyBufToStruct(dataPtr, sonde);

			// write the data packet to the output file
			of << setprecision(15) 
				<< (float) line.timeOfDay << CSV_CHAR;
			of << inet_ntoa(line.from) << CSV_CHAR
				<< inet_ntoa(line.to) << CSV_CHAR;
			of << setprecision(15) 
				<< (float) cmd.cmd() << CSV_CHAR
				<< (float) cmd.seq() << CSV_CHAR
				<< (int)   sonde.id << CSV_CHAR
				<< (int)   sonde.gps.utc.hours << CSV_CHAR
				<< (int)   sonde.gps.utc.minutes << CSV_CHAR
				<< (float)   sonde.gps.utc.seconds << CSV_CHAR
				<< (float)   sonde.gps.pos.lat << CSV_CHAR
				<< (float)   sonde.gps.pos.lon << CSV_CHAR
				<< (float)   sonde.gps.pos.alt << CSV_CHAR
				<< (float)   sonde.gps.track << CSV_CHAR
				<< (float)   sonde.gps.sog << CSV_CHAR
				<< (float)   sonde.pth.pressure << CSV_CHAR
				<< (float)   sonde.pth.temp << CSV_CHAR
				<< (float)   sonde.pth.internal_temp << CSV_CHAR
				<< (float)   sonde.pth.rh1 << CSV_CHAR
				<< (float)   sonde.pth.rh2 << CSV_CHAR
				<< endl;
			break;

		case CMD_WIND:
			WindData_t wind;
			CopyBufToStruct(dataPtr, wind);

			// write the data packet to the output file
			of << setprecision(15) 
				<< (float) line.timeOfDay << CSV_CHAR;
			of << inet_ntoa(line.from) << CSV_CHAR
				<< inet_ntoa(line.to) << CSV_CHAR;
			of << setprecision(15) 
				<< (float) cmd.cmd() << CSV_CHAR
				<< (float) cmd.seq() << CSV_CHAR
				<< (float) wind.south << CSV_CHAR
				<< (float) wind.west << CSV_CHAR
				<< (int)   wind.gps.utc.hours << CSV_CHAR
				<< (int)   wind.gps.utc.minutes << CSV_CHAR
				<< (float) wind.gps.utc.seconds << CSV_CHAR
				<< (float) wind.gps.pos.lat << CSV_CHAR
				<< (float) wind.gps.pos.lon << CSV_CHAR
				<< (float) wind.gps.pos.alt << CSV_CHAR
				<< (float) wind.gps.track << CSV_CHAR
				<< (float) wind.gps.sog << CSV_CHAR
				<< endl;
			break;

		case CMD_LINK_STATUS: 
			{
				int num = cmd.size() / sizeof(LinkStatus_t);
				LinkStatus_t link[num];
				//CopyBufToStruct(dataPtr, link[0]);

				for( int z=0; z < num; z++ ) {
					link[z] = *((LinkStatus_t *)(dataPtr + z*sizeof(LinkStatus_t)));
					CopyBufToStruct(dataPtr, link[0]);
					// write the data packet to the output file
					of << setprecision(15) 
						<< (float) line.timeOfDay << CSV_CHAR;
					of << inet_ntoa(line.from) << CSV_CHAR
						<< inet_ntoa(line.to) << CSV_CHAR;
					of << setprecision(15) 
						<< (float) cmd.cmd() << CSV_CHAR
						<< (float) cmd.seq() << CSV_CHAR;

					of << hex <<setw(2) << setfill('0') << (int)link[z].mac[0];
					for(int ii=1; ii<6; ii++)
						of << ":" << hex <<setw(2) << setfill('0') << (int)link[z].mac[ii];
					of << dec << CSV_CHAR;

					of << (int)link[z].ip[0];
					for(int ii=1; ii<4; ii++)
						of << "." << (int)link[z].ip[ii];
					of << CSV_CHAR;

					of <<  (float)link[z].signal << CSV_CHAR
						//<<  (float)link[z].avg_signal << CSV_CHAR
						<<  (float)link[z].noise << CSV_CHAR
						//<<  (float)link[z].avg_noise << CSV_CHAR
						<<  (float)link[z].channelCap << CSV_CHAR
						<<  (float)link[z].numBytesTx << CSV_CHAR
						<<  (float)link[z].numBytesRx << CSV_CHAR
						<<  (float)link[z].rateTx << CSV_CHAR
						<<  (float)link[z].rateRx << CSV_CHAR
						<<  (float)link[z].last_rx << CSV_CHAR
						<< endl;
				}
				break;
			}

		case CMD_CAPABILITY:
			VehicleInfo_t info;
			CopyBufToStruct(dataPtr, info);

			// write the data packet to the output file
			of << setprecision(15) 
				<< (float) line.timeOfDay << CSV_CHAR;
			of << inet_ntoa(line.from) << CSV_CHAR
				<< inet_ntoa(line.to) << CSV_CHAR;
			of << setprecision(15) 
				<< (float) cmd.cmd() << CSV_CHAR
				<< (float) cmd.seq() << CSV_CHAR;
			of << info.id << CSV_CHAR << "Capabilities"
				<< endl;
			break;

		case CMD_ACK:
			of << setprecision(15) 
				<< (float) line.timeOfDay << CSV_CHAR;
			of << inet_ntoa(line.from) << CSV_CHAR
				<< inet_ntoa(line.to) << CSV_CHAR;
			of << setprecision(15) 
				<< (int) cmd.cmd() << CSV_CHAR
				<< (int) cmd.seq() << CSV_CHAR 
				<< "CMD_ACK" << CSV_CHAR
				<< (int) cmd.param(0) << CSV_CHAR 
				<< endl;
			break;

		case CMD_FAIL:
			of << setprecision(15) 
				<< (float) line.timeOfDay << CSV_CHAR;
			of << inet_ntoa(line.from) << CSV_CHAR
				<< inet_ntoa(line.to) << CSV_CHAR;
			of << setprecision(15) 
				<< (float) cmd.cmd() << CSV_CHAR
				<< (float) cmd.seq() << CSV_CHAR
				<< "CMD_FAIL" << CSV_CHAR
				<< (int) cmd.param(0) << CSV_CHAR 
				<< endl;
			break;

		case CMD_FP:
			cout << "------------- CMD_FP not processed ----------------\n";
			of << setprecision(15) 
				<< (float) line.timeOfDay << CSV_CHAR;
			of << inet_ntoa(line.from) << CSV_CHAR
				<< inet_ntoa(line.to) << CSV_CHAR;
			of << setprecision(15) 
				<< (float) cmd.cmd() << CSV_CHAR
				<< (float) cmd.seq() << CSV_CHAR
				<< "CMD_FP"
				<< endl;
			break;

		case CMD_CHAIN:
			cout << "------------- CMD_CHAIN not processed ----------------\n";
			of << setprecision(15) 
				<< (float) line.timeOfDay << CSV_CHAR;
			of << inet_ntoa(line.from) << CSV_CHAR
				<< inet_ntoa(line.to) << CSV_CHAR;
			of << setprecision(15) 
				<< (float) cmd.cmd() << CSV_CHAR
				<< (float) cmd.seq() << CSV_CHAR
				<< "CMD_CHAIN"
				<< endl;
			break;


		default:
			cout << "-------------DEFAULT----------------\n";
			cout << hex << "<--- Unknown command: CMD=0x" << (int)cmd.cmd()
				<< " --->" << dec << flush << endl;
	}
}
